
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEngine;
using System.Globalization;
using System.Linq;
using System.Diagnostics;
using OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;

namespace ABA
{
    public class ProtoGenerateWin : EditorWindow
    {
        [MenuItem("ABA/Proto协议生成", false, 1)]
        public static void ProtoWinTool()
        {
            // Application.OpenURL(Path.Combine(Application.dataPath, "../../CombaProtobuf/gen_pb_code.bat"));
            GetWindow<ProtoGenerateWin>(false, "Proto工具", true);

        }

        private void OnGUI()
        {
            // 配置目录
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("打开设置", GUILayout.Width(90)))
            {
                SettingWnd.ShowWindow(Path_ProtoWin.TAG);
            }
            EditorGUILayout.EndHorizontal();

            GUILayout.Space(50);
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button($"Proto生成", GUILayout.Height(50)))
            {
                ProtoGen();
                ProtoEventGen();

                EditorUtility.DisplayDialog("提示", $"Proto生成完毕!", "好吧"); 
            }
            EditorGUILayout.EndHorizontal();
        }

        private void ProtoGen()
        {
            var protoFolder = Path_ProtoWin.ProtoFolder;
            var genCSharpFolder = Path_ProtoWin.GenCSharpFolder;

            var files = new List<string>();
            GetFirstExtFiles(protoFolder, ".exe", files);
            if(files.Count <= 0) {
                EditorUtility.DisplayDialog("提示", $"{protoFolder}下没有找到protoc.exe", "好吧"); 
                return;
            }

            var exePath = files[0];
            string[] protoFiles = Directory.GetFiles(protoFolder, "*.proto", SearchOption.TopDirectoryOnly);
            foreach (string file in protoFiles)
            {
                string arguments = $"-I={protoFolder} --csharp_out={genCSharpFolder} {file}";
                // Logger.Log("333:" + file);
                ProtocExe(exePath, arguments);
            }
            Logger.Log("proto 消息文件生成完毕!");
        }

        struct ProtoEventST
        {
            public string cmd;
            public string proto;
            public string desc;
            public string nameSpace;
        }

        void ProtoEventGen()
        {
            var protoFolder = Path_ProtoWin.ProtoFolder;
            var genCSharpFolder = Path_ProtoWin.GenCSharpFolder;
            string[] protoFiles = Directory.GetFiles(protoFolder, "*.proto", SearchOption.TopDirectoryOnly);
            List<ProtoEventST> cmdMap = new List<ProtoEventST>();
            foreach (string file in protoFiles) {
                var lineAry = File.ReadAllLines(file);
                string nameSpace = "";
                for (int i = 0; i < lineAry.Length; i++)
                {
                    var line = lineAry[i];
                    line = line.TrimStart();
                    if(nameSpace == "" && line.IndexOf("package") != -1){
                        line = line.Replace(" ", "");
                        nameSpace = line.Substring(7); // del package
                        // 去掉最后一个字符;
                        nameSpace = nameSpace.Substring(0, nameSpace.Length - 1);
                    }
                    else
                    {
                        line = line.Replace(" ", "");
                        if(line.IndexOf("//cmd:") != -1){
                            var cmd = line.Split(':')[1];
                            var cmdxx = StringUtils.SplitString(cmd, "&&");
                            var nextLine = lineAry[i + 1];
                            nextLine = nextLine.Replace(" ", "");
                            var proto = nextLine.Substring(7); // del message
                            var desc = cmdxx.Length > 1 ? cmdxx[1] : "";
                            cmdMap.Add(new ProtoEventST() {cmd = cmdxx[0], proto = proto, desc = desc, nameSpace = nameSpace});
                        }                         
                    }
                }
            } 

            string eventNetList = "";
            string eventNetTypeList = "";
            string typeNetEventList = "";
            for (int i = 0; i < cmdMap.Count; i++)
            {
                // Logger.Log($"{cmdMap[i].cmd} {cmdMap[i].proto} {cmdMap[i].desc}");
                var cmd = cmdMap[i];
                var item = new StringBuilder();
                item.Append(templateItem);
                item.Replace("{COMMENT}", cmd.desc);
                item.Replace("{NAME}", cmd.proto.ToUpper());
                item.Replace("{CMD}", cmd.cmd);
                string result = item.ToString();
                eventNetList += result;

                var type = new StringBuilder();
                type.Append(templateType);
                type.Replace("{NAMESPACE}", cmd.nameSpace);
                type.Replace("{PROTO_CLASS}", cmd.proto);
                type.Replace("{PROTO}", cmd.proto.ToUpper());
                string result1 = type.ToString();
                eventNetTypeList += result1;

                var etype = new StringBuilder();
                etype.Append(templateEvent);
                etype.Replace("{NAMESPACE}", cmd.nameSpace);
                etype.Replace("{PROTO_CLASS}", cmd.proto);
                etype.Replace("{PROTO}", cmd.proto.ToUpper());
                string result2 = etype.ToString();

                typeNetEventList += result2;
            }

            var builder = new StringBuilder();
            builder.Append(template);
            builder.Replace("{EVENT_NET_LIST}", eventNetList);
            builder.Replace("{REG_EVENT_TYPE_LIST}", eventNetTypeList);
            builder.Replace("{REG_TYPE_EVENT_LIST}", typeNetEventList);
            builder.Replace("{TIME_SHOW}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            string content = builder.ToString();

            File.WriteAllText(genCSharpFolder + "/../ProtoEvent.cs", content);

            Logger.Log("ProtoEvent 文件生成完毕!");
        }

        void ProtocExe(string exePath, string arguments){
            // Logger.Log("exePath:" + exePath);
            // Logger.Log("arguments:" + arguments);
            // Create a new ProcessStartInfo object
            ProcessStartInfo startInfo = new ProcessStartInfo
            {
                FileName = exePath,
                Arguments = arguments,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            };

            // Start the process
            Process process = new Process
            {
                StartInfo = startInfo
            };

            process.Start();

            // Read the output of the process
            string output = process.StandardOutput.ReadToEnd();

            // Wait for the process to exit
            process.WaitForExit();

            // Get the exit code of the process
            int exitCode = process.ExitCode;

            // Do something with the output and exit code
            // Logger.Log($"Output: {output}");
            // Logger.Log($"Exit Code: {exitCode}");  
        }

        void GetFirstExtFiles(string directoryPath, string extName, List<string> pathList)
        {
            // 获取文件夹下所有文件
            string[] files = Directory.GetFiles(directoryPath);

            foreach (string file in files)
            {
                // 检查文件是否为.exe
                if (Path.GetExtension(file) == extName)
                {
                    // Logger.Log(file);
                    pathList.Add(file);
                }
            }

            // 递归获取子文件夹下的文件
            string[] subdirectories = Directory.GetDirectories(directoryPath);

            foreach (string subdirectory in subdirectories)
            {
                GetFirstExtFiles(subdirectory, extName, pathList);
            }
        }

        public const string templateItem = @"
    /// <summary>
    /// {COMMENT}
    /// </summary>
    public const int EVENT_NET_{NAME} = {CMD};
";

        public const string templateType = @"
        eventTypeDic[typeof({NAMESPACE}.{PROTO_CLASS})] = EVENT_NET_{PROTO};
";
        public const string templateEvent = @"
        typeEventDic[EVENT_NET_{PROTO}] = typeof({NAMESPACE}.{PROTO_CLASS});
";

        public const string template = @"
//-----------Auto Generate ByTools-----------
//-----------Time:{TIME_SHOW}-----------
//-----------Don't change-----------
using System;
using System.Collections.Generic;

public static class ProtoEvent
{
    {EVENT_NET_LIST}

    public static int GetEventId(Type type)
    {
        if(eventTypeDic.Count == 0) RegEventType();
        
        if (eventTypeDic.ContainsKey(type))
        {
            return eventTypeDic[type];
        }
        return -1;
    }

    static Dictionary<Type, int> eventTypeDic = new Dictionary<Type, int>();
    public static void RegEventType()
    {
        {REG_EVENT_TYPE_LIST}
    }

    public static Type GetTypeFromEventId(int eventId)
    {
        if(typeEventDic.Count == 0) RegTypeEvent();
        
        if (typeEventDic.ContainsKey(eventId))
        {
            return typeEventDic[eventId];
        }
        return null;
    }

    static Dictionary<int, Type> typeEventDic = new Dictionary<int, Type>();
    public static void RegTypeEvent()
    {
        {REG_TYPE_EVENT_LIST}
    }

}
//-----------End-----------
";


    }
}
